package com.ry.video;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

public class VideoSubtitleGenerator {

    public static void main(String[] args) {
        try {
            // 设置文件路径
            String videoPath = "./srt_input/3fb8b827-9568-4e4d-9432-9381115d40ef.mp4";
            String audioPath = "./srt_input/5月3日.MP3";
            String textPath = "./srt_input/5 月 3 日.txt";
            String outputPath = "./srt_output/final_video.mp4";

            // 确保输出目录存在
            File outputDir = new File(outputPath).getParentFile();
            if (!outputDir.exists()) {
                outputDir.mkdirs();
            }

            // 生成带字幕的视频
            generateVideoWithSubtitles(videoPath, audioPath, textPath, outputPath);

            System.out.println("视频字幕生成完成!");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void generateVideoWithSubtitles(String videoPath, String audioPath, String textPath, String outputPath) throws Exception {
        // 读取文本文件
        String text = new String(Files.readAllBytes(Paths.get(textPath)), StandardCharsets.UTF_8);
        System.out.println("读取的文本内容: " + text);

        // 分割文本为句子
        List<String> sentences = splitSentences(text);
        System.out.println("分割后的句子: " + sentences);

        // 获取音频时长
        double totalDuration = getAudioDuration(audioPath);

        // 计算每个句子的持续时间
        double sentenceDuration = totalDuration / sentences.size();

        // 生成SRT字幕文件
        String srtPath = generateSrtFile(sentences, sentenceDuration, outputPath);

        // 合并视频、音频和字幕
        mergeVideoAudioSubtitles(videoPath, audioPath, srtPath, outputPath);
    }

    private static List<String> splitSentences(String text) {
        List<String> sentences = new ArrayList<>();
        // 使用多种分隔符分割文本
        Pattern pattern = Pattern.compile("[。，；｜]");
        String[] parts = pattern.split(text);

        for (String part : parts) {
            String sentence = part.trim();
            if (!sentence.isEmpty()) {
                sentences.add(sentence);
            }
        }

        return sentences;
    }

    private static double getAudioDuration(String audioPath) throws IOException, InterruptedException {
        // 调用ffprobe获取音频时长
        ProcessBuilder pb = new ProcessBuilder(
                "ffprobe",
                "-v", "error",
                "-show_entries", "format=duration",
                "-of", "default=noprint_wrappers=1:nokey=1",
                audioPath
        );

        Process process = pb.start();
        BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
        String durationStr = reader.readLine();
        process.waitFor();

        return Double.parseDouble(durationStr);
    }

    private static String generateSrtFile(List<String> sentences, double sentenceDuration, String outputPath) throws IOException {
        String srtPath = outputPath.replaceFirst("[.][^.]+$", ".srt");

        StringBuilder srtContent = new StringBuilder();
        for (int i = 0; i < sentences.size(); i++) {
            double startTime = i * sentenceDuration;
            double endTime = (i + 1) * sentenceDuration;

            srtContent.append(i + 1).append("\n");
            srtContent.append(formatSrtTime(startTime)).append(" --> ").append(formatSrtTime(endTime)).append("\n");
            srtContent.append(sentences.get(i)).append("\n\n");
        }

        Files.write(Paths.get(srtPath), srtContent.toString().getBytes(StandardCharsets.UTF_8));
        return srtPath;
    }

    private static String formatSrtTime(double time) {
        int totalSeconds = (int) time;
        int hours = totalSeconds / 3600;
        int minutes = (totalSeconds % 3600) / 60;
        int seconds = totalSeconds % 60;
        int milliseconds = (int) ((time - totalSeconds) * 1000);

        return String.format("%02d:%02d:%02d,%03d", hours, minutes, seconds, milliseconds);
    }

    private static void mergeVideoAudioSubtitles(String videoPath, String audioPath, String srtPath, String outputPath) throws IOException, InterruptedException {
        // 构建FFmpeg命令
        List<String> command = new ArrayList<>();
        command.add("ffmpeg");
        command.add("-i");
        command.add(videoPath);
        command.add("-i");
        command.add(audioPath);
        command.add("-vf");
        command.add("subtitles=" + escapePath(srtPath) +
                ":force_style='Fontname=SimHei,Fontsize=48,PrimaryColour=&HFFFFFF,BackColour=&H000000,BorderStyle=3,Outline=2,MarginV=20'");
        command.add("-c:v");
        command.add("libx264");
        command.add("-c:a");
        command.add("aac");
        command.add("-shortest");
        command.add("-y");
        command.add(outputPath);

        // 执行FFmpeg命令
        ProcessBuilder pb = new ProcessBuilder(command);
        pb.inheritIO(); // 继承标准输入输出
        Process process = pb.start();
        int exitCode = process.waitFor();

        if (exitCode != 0) {
            throw new IOException("FFmpeg命令执行失败，退出码: " + exitCode);
        }
    }

    private static String escapePath(String path) {
        // 转义路径中的特殊字符
        return path.replace("\\", "\\\\").replace(":", "\\:");
    }
}